package cn.buk.qms.service;

import cn.buk.api.airskyhk.dto.*;
import cn.buk.api.wechat.dto.WxTemplateDataParam;
import cn.buk.api.wechat.dto.WxTemplateSend;
import cn.buk.common.JsonResult;
import cn.buk.common.dto.CommonDto;
import cn.buk.common.flight.dto.FlightBasicInfo;
import cn.buk.common.util.FlightTicketUtil;
import cn.buk.qms.SmsUtil;
import cn.buk.tms.dto.CustomerServiceTemplateDto;
import cn.buk.tms.dto.FlightRefundOrderDetailDto;
import cn.buk.tms.dto.FlightRefundOrderDto;
import cn.buk.tms.dto.FlightRefundTicket;
import cn.buk.tms.dao.FlightOrderDao;
import cn.buk.tms.dao.FlightRefundOrderDao;
import cn.buk.tms.entity.config.EnterpriseConfig;
import cn.buk.tms.entity.misc.*;
import cn.buk.tms.entity.order.OrderAttachment;
import cn.buk.tms.entity.order.OrderNoInfo;
import cn.buk.tms.sc.SearchFlightOrderCriteria;
import cn.buk.tms.dto.SmsDetailDto;
import cn.buk.tms.entity.bill.BillInfo;
import cn.buk.tms.entity.misc.FlightInfo;
import cn.buk.tms.entity.order.flight.FlightOrder;
import cn.buk.tms.entity.order.flight.FlightRefundOrder;
import cn.buk.tms.entity.order.flight.FlightRefundOrderDetail;
import cn.buk.tms.flight.service.EtermService;
import cn.buk.tms.flight.util.FlightOrderUtil;
import cn.buk.tms.flight.dto.response.RefundOrderResponseDto;
import cn.buk.common.util.CheckUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static cn.buk.common.Constant.SUCCESS;
import static cn.buk.tms.entity.config.EnterpriseConfig.TMS_DEFAULT_LINK_MOBILE;
import static cn.buk.tms.common.constant.TmsOrderConstant.ORDER_TYPE_FLIGHT_REFUND;

@Service
public class FlightRefundOrderServiceImpl extends BaseOrderService implements FlightRefundOrderService {

  private static final Logger logger = LogManager.getLogger(FlightRefundOrderServiceImpl.class);

  private static final String REFUND_SMS_TEMPLATE_1 = "%s乘机人：%s，原行程：%s，票号：%s，已成功退票，退票费：%s元。";

  @Autowired
  private FlightRefundOrderDao dao;

  @Autowired
  private FlightOrderDao flightOrderDao;

  @Autowired
  private EtermService etermService;

  @Override
  @Secured({"ROLE_OPERATOR", "ROLE_SUPERVISOR", "ROLE_ADMIN"})
  public JsonResult createFlightRefundOrder(int enterpriseId, String username, FlightRefundOrderDto dto) {
    final String ticketNo0 = dto.getTicketNo();

    if (!FlightTicketUtil.verifyTicketNo(ticketNo0)) {
      return JsonResult.createJsonResult(-1, "票号格式不符合要求");
    }

    final String balCode = ticketNo0.substring(0, 3);
    final String tickNo = ticketNo0.length() == 14 ? ticketNo0.substring(4) : ticketNo0.substring(3);

    // 检查该票号是否已经退票订单
    SearchFlightOrderCriteria sc = new SearchFlightOrderCriteria();
    sc.setBalCode(balCode);
    sc.setTicketNo(tickNo);
    List<FlightRefundOrder> orders = dao.searchFlightRefundOrder(enterpriseId, sc, null);
    if (!orders.isEmpty()) {
      return JsonResult.createJsonResult(-2, "该票号已经创建了退票单");
    }

    if (dto.getOrderId() == 0 && dto.getOrderNo().length() == 0) {
      //手工录入的退票单
      if (dto.getCustomerId() < 0 || dto.getSupplierId() < 1 || dto.getPaymentId() < 1) {
        return JsonResult.createJsonResult(-3, "客户，供应商，支付方式都需要选择");
      }
    }

    int retCode = doCreateRefundOrder(enterpriseId, username, balCode, tickNo, dto.getName(), dto.getIdNo(), dto);

    JsonResult jsonResult = JsonResult.createJsonResult(retCode);

    if (retCode > 0) {
      jsonResult.setReturnCode(retCode);
    } else if (retCode == -100) {
      jsonResult.setErrmsg("保存时出现错误，请检查是否已有退票单。");
    }

    return jsonResult;
  }

  /**
   * 同时创建多张退票单
   */
  @Override
  @Secured({"ROLE_OPERATOR", "ROLE_SUPERVISOR", "ROLE_ADMIN"})
  public JsonResult createFlightRefundOrderV2(int enterpriseId, String username, FlightRefundOrderDto dto) {
    if (dto.getRefundTickets().isEmpty()) {
      return JsonResult.createJsonResult(-1, "请选择需要退票的票号");
    }

    //筛选
    var selectedTickets =  dto.getRefundTickets().stream()
            .filter(FlightRefundTicket::isSelected)
            .collect(Collectors.toList());

    if (selectedTickets.isEmpty()) {
      return JsonResult.createJsonResult(-2, "请选择需要退票的票号");
    }

    for (FlightRefundTicket t : selectedTickets) {
      if (!FlightTicketUtil.verifyTicketNo(t.getTicketNo())
              && !FlightTicketUtil.verifyConnectionTicketNo(t.getTicketNo())
      ) {
        return JsonResult.createJsonResult(-1, "票号格式不符合要求");
      }

      final String balCode = t.getTicketNo().substring(0, 3);
      final String tickNo = getTenTicketNo(t.getTicketNo());

      // 检查该票号是否已经退票订单
      SearchFlightOrderCriteria sc = new SearchFlightOrderCriteria();
      sc.setBalCode(balCode);
      sc.setTicketNo(tickNo);
      List<FlightRefundOrder> orders = dao.searchFlightRefundOrder(enterpriseId, sc, null);
      if (!orders.isEmpty()) {
        return JsonResult.createJsonResult(-2, balCode + tickNo + "-该票号已经创建了退票单");
      }
    }

    int created = 0;
    int retCode = 0;
    for (FlightRefundTicket t : selectedTickets) {
      final String balCode = t.getTicketNo().substring(0, 3);
      final String tickNo = getTenTicketNo(t.getTicketNo());

      retCode = doCreateRefundOrder(enterpriseId, username, balCode, tickNo, t.getName(), t.getIdNo(), dto);
      if (retCode > 0) {
        created++;
      }
    }

    JsonResult jsonResult = JsonResult.createJsonResult(created);
    if (retCode > 0) {
      jsonResult.setReturnCode(retCode);
    } else if (retCode == -100) {
      jsonResult.setErrmsg("保存时出现错误，请检查是否已有退票单。");
    }

    return jsonResult;
  }

  /**
   * 获取10位票号(第一个10位）
   *
   * @param tempTicketNo 可能是联程票号：781-1234567891-92
   */
  private String getTenTicketNo(String tempTicketNo) {
    //删除前3位
    tempTicketNo = tempTicketNo.substring(3);
    if ("-".equalsIgnoreCase(tempTicketNo.substring(0, 1))) {
      tempTicketNo = tempTicketNo.substring(1);
    }

    return tempTicketNo.substring(0, 10);
  }

  private int doCreateRefundOrder(final int enterpriseId, final String username, final String balCode, final String tickNo,
                                  final String psgName, final String idNo, final FlightRefundOrderDto dto) {
    FlightRefundOrder info = new FlightRefundOrder();

    info.setEnterpriseId(enterpriseId);
    info.setBalanceCode(balCode);
    info.setTicketNo(tickNo);

    info.setPsgName(psgName);
    info.setIdNo(idNo);

    info.setParvalue(dto.getParvalue());
    info.setTax(dto.getTax());
    info.setCost(dto.getCost());
    info.setTicketAmount(dto.getAmount());
    info.setAirRefundCharge(dto.getAirRefundFee());
    info.setServiceCharge(dto.getServiceCharge());


    info.setRemark(dto.getRemark());
    info.setOperator(username);

    info.setReasonCode(dto.getReasonCode());
    info.setReasonDesc(dto.getReasonDesc());

    //TODO orderId 和 orderNo 必须传一个值过来，预下的相关的订单内容后台在数据库中获取，不依赖前台传递的值  yfdai 2021-09-17
    info.setOrderId(dto.getOrderId());
    info.setOrderNo(dto.getOrderNo());

    info.setIntlTicket(dto.getIntlTicket());

    info.setRefundOrderNo(orderNoGenerator.generateOrderNo(enterpriseId, OrderNoInfo.ORDER_FLIGHT_REFUND));

    if (dto.getOrderId() > 0 || dto.getOrderNo().length() > 0) {
      FlightOrder flightOrder = null;
      if (dto.getOrderId() > 0) {
        flightOrder = flightOrderDao.getOrderDetailById(dto.getOrderId());
      } else if (dto.getOrderNo().length() > 0) {
        flightOrder = flightOrderDao.getOrderDetailByOrderNo(enterpriseId, dto.getOrderNo());
      }

      if (flightOrder != null) {
        var t1 = info;
        var t0 = flightOrder;

        t1.setCustomerType(t0.getCustomerType());
        t1.setCustomer(t0.getCustomer());

        t1.setCostCenter(t0.getCostCenter());
        t1.setProjectName(t0.getProjectName());

        t1.setSupplier(t0.getSupplier());
        t1.setPaymentMethod(t0.getPaymentMethod());

        t1.setPayType(t0.getPayType());
        t1.setPayRemark(t0.getPayRemark());

        info.setPnrNo(flightOrder.getPnrNo());
      }
    } else {
      //手工录入的
      if (dto.getCustomerId() < 1) {
        //散客
        info.setCustomerType(0);
      } else {
        //企业客户
        info.setCustomerType(1);
        Customer customer = customerDao.getCustomerById(dto.getCustomerId());
        info.setCustomer(customer);

        Supplier supplier = enterpriseDao.getSupplierById(dto.getSupplierId());
        info.setSupplier(supplier);

        PaymentMethod pm = enterpriseDao.getPaymentMethodById(dto.getPaymentId());
        info.setPaymentMethod(pm);
      }
    }


    for (FlightRefundOrderDetailDto detailDto : dto.getFlights()) {
      FlightRefundOrderDetail detail = new FlightRefundOrderDetail();
      detail.setOrder(info);
      detail.setEnterpriseId(enterpriseId);

      FlightInfo flt = detail.getFlight();

      flt.setDepartureAirport(detailDto.getDport());
      flt.setDepartureAirportName(detailDto.getDportName());
      flt.setDepartureTerminal(detailDto.getDterm());
      flt.setArrivalAirport(detailDto.getAport());
      flt.setArrivalAirportName(detailDto.getAportName());
      flt.setArrivalTerminal(detailDto.getAterm());
      flt.setDepartureDate(detailDto.getDdate());
      flt.setDepartureTime(detailDto.getDtime());
      flt.setArrivalTime(detailDto.getAtime());
      flt.setSubclass(detailDto.getSubclass());
      flt.setFlightNo(detailDto.getFlightNo());

      info.getFlights().add(detail);
    }

    int retCode = dao.createFlightRefundOrder(info);

    if (retCode > 0) {
      try {
        //发送给群聊会话
        final String content = String.format("有新的退票单了(%s, %s).", info.getRefundOrderNo(), info.getSupplier().getName());
        sendRefundOrderAlertToWwAppChat(enterpriseId, content);
      } catch (Exception ex) {
        logger.error(ex.getMessage());
      }
    }

    return retCode;
  }

  @Override
  @Secured({"ROLE_TICKETER", "ROLE_SUPERVISOR", "ROLE_ADMIN"})
  public JsonResult processFlightRefund(int enterpriseId, String operator, int orderId) {
    //TODO 将检查退票单的供应商和乘机人的联系电话检查更新放在此处 yfdai 2021-10-17
    return JsonResult.createJsonResult(dao.processFlightRefund(enterpriseId, operator, orderId));
  }

  @Override
  @Secured({"ROLE_SUPERVISOR", "ROLE_ADMIN"})
  public JsonResult cancelFlightRefund(int enterpriseId, String operator, int id) {
    return JsonResult.createJsonResult(dao.cancelFlightRefund(enterpriseId, operator, id));
  }

  @Override
  @Secured({"ROLE_SUPERVISOR", "ROLE_ADMIN"})
  public JsonResult reopenFlightRefund(int enterpriseId, String operator, int id) {
    return JsonResult.createJsonResult(dao.reopenFlightRefund(enterpriseId, operator, id));
  }

  @Override
  @Secured({"ROLE_TICKETER", "ROLE_SUPERVISOR", "ROLE_ADMIN"})
  public JsonResult submitFlightRefund(final int enterpriseId, final String username, final int orderId) {
    FlightRefundOrder o = dao.getFlightRefundOrderDetail(orderId);

    //校验服务费是否符合服务费模板设置
    JsonResult v = validateRefundOrderServiceCharge(enterpriseId, o);
    if (v != null) {
      return v;
    }

    return JsonResult.createJsonResult(dao.submitFlightRefund(enterpriseId, username, orderId));
  }

  /**
   * 校验退票订单的服务费
   */
  private JsonResult validateRefundOrderServiceCharge(final int enterpriseId, FlightRefundOrder o) {
    if (o.getCustomer() == null || o.getCustomer().getTemplateCode() == null) {
      return null;
    }
    final String tplCode = o.getCustomer().getTemplateCode();
    CustomerServiceTemplate tpl = enterpriseDao.searchCustomerServiceTemplate(enterpriseId, tplCode);
    if (tpl == null) {
      doSendAlert(enterpriseId, "退票单(" + o.getOrderNo() + ")提交时, 未找到服务费模板(" + tplCode + ").", "Dai", 0);
      return null;
    }

    CustomerServiceTemplateDto tplDto = CustomerServiceTemplateDto.createBy(tpl);
    //退票服务费
    int refundFee = tplDto.getFlightRefundFee();
    List<CustomerServiceFlightRule> flightRules = enterpriseDao.searchCustomerServiceFlightRules(enterpriseId, tplDto.getTemplateCode());
    for (CustomerServiceFlightRule fltRule : flightRules) {
      for (FlightRefundOrderDetail flt : o.getFlights()) {
        if (fltRule.getCarrier().equalsIgnoreCase(flt.getFlight().getFlightNo().substring(0, 2))
                && fltRule.getSubclasses().contains(flt.getFlight().getSubclass())) {
          //使用具体航司的具体舱位的服务费规则
          refundFee = fltRule.getFlightRefundFee();
          break;
        }
      }
    }

    if (refundFee > 0 && Math.abs(refundFee - o.getServiceCharge()) > 0.001) {
      final String content = String.format("退票单(%s): 服务费模板(%d)设定服务费为(%d), 实际(%f).",
              o.getOrderNo(), tpl.getStrength(), refundFee, o.getServiceCharge());
      doSendAlert(enterpriseId, content, null, EntDepartment.DEPT_ADMINISTRATOR);
      if (tpl.getStrength() == 10) {
        return JsonResult.createJsonResult(-2, content);
      }
    }

    return null;
  }

  /**
   * 设置退票单的航司预退金额
   */
  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_TICKETER})
  public JsonResult setFlightRefundAirlineRefundedAmount(final int enterpriseId, final String username, final int id, final double amount) {
    if (amount < 0) {
      return JsonResult.createJsonResult(-1, "航司预退金额不能为负数");
    }

    if (amount >= 0 && amount < 0.0001) {
      FlightRefundOrder info = dao.getFlightRefundOrderDetail(id);
      if (info != null) {
        String remark = "用户(" + username + ")将退票单(" + info.getRefundOrderNo() + ")的航司预退金额设置为" + amount + ".";
        doSendAlert(enterpriseId, remark, null, EntDepartment.DEPT_ADMINISTRATOR);
      }
    }

    int retCode = dao.setFlightRefundAirlineRefundedAmount(enterpriseId, username, id, amount);
    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 航司已退状态
   */
  @Override
  @Secured({"ROLE_TICKETER", "ROLE_SUPERVISOR", "ROLE_ADMIN", RoleInfo.ROLE_CASHIER})
  public JsonResult setFlightRefundAirlineRefundedStatus(int enterpriseId, String username, int id) {
    int retCode = dao.setFlightRefundAirlineRefundedStatus(enterpriseId, username, id);
    if (retCode == FlightRefundOrder.ORDER_STATUS_DONE) {
      importService.importFlightRefundOrder(enterpriseId, username, id);
    }

    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 已退客户
   *
   * @param enterpriseId 当前用户的enterpriseId
   * @param username     当前用户的用户名
   * @param id           退票单id
   * @param amount       航司实退金额
   */
  @Override
  @Secured({"ROLE_CASHIER", "ROLE_SUPERVISOR", "ROLE_ADMIN"})
  public JsonResult setFlightRefundPassengerRefundedAmount(int enterpriseId, String username, int id, double amount) {
    if (amount < 0) {
      return JsonResult.createJsonResult(-1, "请输入实退金额");
    }

    int retCode = dao.setFlightRefundPassengerRefundedAmount(enterpriseId, username, id, amount);
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  @Secured({"ROLE_CASHIER", "ROLE_SUPERVISOR", "ROLE_ADMIN"})
  public JsonResult setFlightRefundPassengerRefundedStatus(int enterpriseId, String username, int id) {
    int retCode = dao.setFlightRefundPassengerRefundedStatus(enterpriseId, username, id);
    if (retCode == FlightRefundOrder.ORDER_STATUS_DONE) {
      importService.importFlightRefundOrder(enterpriseId, username, id);
    }

    if (retCode > 0) {
      FlightRefundOrder orderInfo = dao.getFlightRefundOrderDetail(id);
      //TODO 发送微信模板消息通知微信用户
      try {
        doSendWeixinTemplateMessage("oEK0T0sye8VHx3ywNellAehPY-8Y", enterpriseId, orderInfo);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
      if (orderInfo.getCustomer() != null && orderInfo.getCustomer().getSmsMode() == 1) {
        dao.appendRefundOrderLog(enterpriseId, username, id, "^_^将自动发送短信");
        this.sendFlightRefundOrderSms(enterpriseId, username, id, null, 0, null);
      } else {
        dao.appendRefundOrderLog(enterpriseId, username, id, "系统设定不需要自动发送短信");
      }
    }

    return JsonResult.createJsonResult(retCode);
  }

  private void doSendWeixinTemplateMessage(final String openid, final int enterpriseId, final FlightRefundOrder refundOrder) {
    WxTemplateSend wxTplRq = new WxTemplateSend();
    wxTplRq.setTouser(openid);
    wxTplRq.setTemplate_id("t6U9egEnOI11PuESI2rn_QkPhS-7uxBM7ix-k1j0e7E");

    String firstData = "您好，已为您办理退票。";
    wxTplRq.getData().setFirst(WxTemplateDataParam.createByValue(firstData));

    wxTplRq.getData().setOrderId(WxTemplateDataParam.createByValue(refundOrder.getOrderNo()));
    var psgNames = refundOrder.getPsgName();

    wxTplRq.getData().setPersonName(WxTemplateDataParam.createByValue(psgNames));

    processOrderAirportName(refundOrder);
    final String smsRouteInfo = SmsUtil.convertRefundOrder(refundOrder);
    wxTplRq.getData().setFlightInfo(WxTemplateDataParam.createByValue(smsRouteInfo));

    final String amountInfo = "退您" + refundOrder.getPassengerRefundAmount() + "元。";
    wxTplRq.getData().setAmount(WxTemplateDataParam.createByValue(amountInfo));

    FlightOrder orderInfo = flightOrderDao.getOrderDetailByOrderNo(enterpriseId, refundOrder.getOrderNo());

    final String url = generateTmsWxsTplUrl(enterpriseId, openid, orderInfo.getId(), OrderNoInfo.ORDER_FLIGHT);
    wxTplRq.setUrl(url);

    doSendWeixinTemplateMessage(enterpriseId, wxTplRq);
  }


  @Override
  public List<RefundOrderResponseDto> searchFlightRefundOrder(final int enterpriseId, final int userId, SearchFlightOrderCriteria sc) {

    List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);

    if (isOnlySeeOwn(enterpriseId, userId)) {
      //仅能查看自己的订单
      User user = userDao.getUserById(userId);
      sc.setOp1(user.getUsername());
    }


    List<FlightRefundOrder> list = dao.searchFlightRefundOrder(enterpriseId, sc, allowedCustomerIds);
    for (FlightRefundOrder info : list) {
      FlightOrderUtil.cleanFlightRefundOrder(info);
    }

    final boolean needHideCustomerName = isNeedHideCustomerName(enterpriseId, userId);
    //隐藏客户名称
    User user = userDao.getUserById(userId);
    for (FlightRefundOrder order : list) {
      maskCustomerName(order.getCustomer(), order.getOperator(), user.getUsername(), needHideCustomerName);
    }

    List<RefundOrderResponseDto> dtos = new ArrayList<>();
    for (FlightRefundOrder o : list) {
      dtos.add(RefundOrderResponseDto.createBy(o));
    }

    //处理机场代码的中文名
    for (RefundOrderResponseDto dto : dtos) {
      for (FlightBasicInfo fltInfo : dto.getFlights()) {
        if (fltInfo.getDportName() == null) {
          //机场中文名
          String name = getAirportName(fltInfo.getDport());
          fltInfo.setDportName(name);
        }
        if (fltInfo.getAportName() == null) {
          //机场中文名
          String name = getAirportName(fltInfo.getAport());
          fltInfo.setAportName(name);
        }
      }
    }

    return dtos;
  }

  @Override
  public CommonDto<RefundOrderResponseDto> searchFlightRefundOrder2(int enterpriseId, int userId, SearchFlightOrderCriteria sc) {
    List<RefundOrderResponseDto> tickets = this.searchFlightRefundOrder(enterpriseId, userId, sc);

    CommonDto<RefundOrderResponseDto> commonDto = new CommonDto<>();
    commonDto.setDataList(tickets);
    commonDto.setPage(sc.getPage());

    return commonDto;
  }

  @Override
  public RefundOrderResponseDto getFlightRefundOrderDetail(int enterpriseId, int userId, int id) {
    FlightRefundOrder o = dao.getFlightRefundOrderDetail(id);

    for (FlightRefundOrderDetail detail : o.getFlights()) {
      detail.setOrder(null);
    }

    List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
    if (!allowedCustomerIds.isEmpty() && o.getCustomer() != null && !allowedCustomerIds.contains(o.getCustomer().getId())) {
      return null;
    }

    //是否要对当前用户隐藏客户名称
    if (isNeedHideCustomerName(enterpriseId, userId)) {
      User user = userDao.getUserById(userId);
      maskCustomerName(o.getCustomer(), o.getOperator(), user.getUsername(), true);
    }

    RefundOrderResponseDto dto = RefundOrderResponseDto.createBy(o);

    //取得相关的 短信
    List<SmsDetail> smsDetails = smsDao.searchSmsByOrderNo(enterpriseId, o.getRefundOrderNo());
    for (SmsDetail sms : smsDetails) {
      SmsDetailDto smsDto = new SmsDetailDto();
      BeanUtils.copyProperties(sms, smsDto);

      dto.getSmsDetails().add(smsDto);
    }

    //获取相关的附件内容
    List<OrderAttachment> attachments = dao.searchAttachments(enterpriseId, o.getId());
    processAttachments(enterpriseId, attachments, dto.getAttachments());


    return dto;
  }

  @Override
  public RefundOrderResponseDto getFlightRefundOrderDetailByRefundOrderNo(int enterpriseId, String refundOrderNo) {
    FlightRefundOrder o = dao.getFlightRefundOrderDetailByRefundOrderNo(enterpriseId, refundOrderNo);

    for (FlightRefundOrderDetail detail : o.getFlights()) {
      detail.setOrder(null);
    }

    return RefundOrderResponseDto.createBy(o);
  }

  @Override
  public List<OperationLog> searchFlightRefundOrderHistory(int enterpriseId, int id) {
    return dao.searchFlightRefundOrderHistory(enterpriseId, id);
  }

  @Override
  public JsonResult updateRefundOrderPrice(int enterpriseId, String username, int id, double airRefundCharge, double serviceCharge) {
    int retCode = dao.updateRefundOrderPrice(enterpriseId, username, id, airRefundCharge, serviceCharge);
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public JsonResult updateRefundOrderRemark(int enterpriseId, String username, int id, String remark) {
    int retCode = dao.updateRefundOrderRemark(enterpriseId, username, id, remark);
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_CASHIER})
  public JsonResult setFinallyAirRefunded(int enterpriseId, String username, int id, double amount) {
    int retCode = dao.setFinallyAirRefunded(enterpriseId, username, id, amount);


    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 回滚状态到"已提交"
   */
  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR})
  public JsonResult rollbackRefundOrderStatus(final int enterpriseId, final String username, final int orderId, final String remark) {
    // 检查是否有对应的账单，如果有，就不能回滚
    FlightRefundOrder refundOrder = dao.getFlightRefundOrderDetail(orderId);
    if (refundOrder == null || refundOrder.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "数据错误");
    }

    List<BillInfo> billInfos = billService.searchBillInfoByOrderNo(enterpriseId, refundOrder.getRefundOrderNo());
    if (!billInfos.isEmpty()) {
      doSendAlert(enterpriseId, "退票单(" + refundOrder.getRefundOrderNo() + ")回滚失败，存在对应的账单", null, EntDepartment.DEPT_ADMINISTRATOR);
      return JsonResult.createJsonResult(-2, "存在对应的账单，不能回滚");
    }

    int retCode = dao.rollbackRefundOrderStatus(enterpriseId, username, orderId, remark);
    if (retCode > 0) {
      doSendAlert(enterpriseId, "退票单(" + refundOrder.getRefundOrderNo() + ")已回滚: " + remark, null, EntDepartment.DEPT_ADMINISTRATOR);
    }
    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 短信内容
   */
  @Override
  public JsonResult getFlightRefundOrderSmsContent(int enterpriseId, String username, int orderId, int smsFormat) {
    var refundOrder = dao.getFlightRefundOrderDetail(orderId);
    if (refundOrder == null) {
      return JsonResult.createJsonResult(-1, "未找到退票单");
    }

    String smsContent = generateSmsContentByTemplate(enterpriseId, smsFormat, refundOrder);

    if (smsContent != null) {
      return JsonResult.createJsonResult(1, smsContent);
    } else {
      return JsonResult.createJsonResult(-1, "无法生成短信内容");
    }
  }

  /**
   * 根据退票单内容发送短信
   */
  @Override
  public JsonResult sendFlightRefundOrderSms(final int enterpriseId, String username, final int orderId, String mobileNo, int smsFormat, String smsContent0) {
    if (mobileNo != null && !CheckUtil.isMobileNo(mobileNo)) {
      return JsonResult.createJsonResult(-3, "无符合要求的手机号");
    }

    FlightRefundOrder refundOrder = dao.getFlightRefundOrderDetail(orderId);
    if (mobileNo == null) {
      mobileNo = refundOrder.getMobile();
      if (!CheckUtil.isMobileNo(mobileNo)) {
        return JsonResult.createJsonResult(-3, "无符合要求的手机号");
      }
    }

    String smsContent = smsContent0 == null || smsContent0.trim().length() == 0 ? generateSmsContentByTemplate(enterpriseId, smsFormat, refundOrder) : smsContent0;

    SmsDetail smsDetail = SmsDetail.createSmsDetail(enterpriseId, username, mobileNo, smsContent, refundOrder.getRefundOrderNo());

    return sendSms(smsDetail);
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN})
  public JsonResult updateRefundOrderTicketNo(int enterpriseId, String username, int orderId,
                                              String ticketNo) {
    //校验票号
    if (!FlightTicketUtil.verifyTicketNo(ticketNo)) {
      return JsonResult.createJsonResult(-1, "票号(" + ticketNo + ")不符合规范");
    }

    final String balCode = ticketNo.substring(0, 3);
    final String tickNo =
            ticketNo.length() == 14 ? ticketNo.substring(4) : ticketNo.substring(3);

    try {
      int retCode = dao.updateRefundOrderTicketNo(enterpriseId, username, orderId, balCode, tickNo);

      if (retCode == 1) {
        doSendAlert(enterpriseId, "退票单(" + orderId + ")的票号修改为：" + ticketNo, null, EntDepartment.DEPT_ADMINISTRATOR);
      }

      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      logger.error(ex.getMessage());
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public void refreshRefundOrderDetrDetail(int enterpriseId, String username) {
    List<FlightRefundOrder> refundOrders = dao.searchRefundOrdersNeedRefreshDetr(enterpriseId, 10);
    logger.info("refreshRefundOrderDetrDetail refundOrder's is {}.", refundOrders.size());

    for (FlightRefundOrder orderInfo : refundOrders) {
      if (orderInfo.getDetrRefreshStatus() != null && orderInfo.getDetrRefreshStatus() != 0) {
        continue;
      }

      if (orderInfo.getStatus() == FlightRefundOrder.ORDER_STATUS_DONE) {
        etermService.refreshRefundOrderDetrDetail(enterpriseId, username, orderInfo);
      }
    }
  }

  @Override
  public JsonResult sendWeixinTplMsg(int enterpriseId, int id) {
    FlightRefundOrder orderInfo = dao.getFlightRefundOrderDetail(id);
    //TODO 发送微信模板消息通知微信用户
    try {
      doSendWeixinTemplateMessage("oEK0T0sye8VHx3ywNellAehPY-8Y", enterpriseId, orderInfo);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return null;
  }

  @Override
  public JsonResult createNdcOrderRefund(final int enterpriseId, final String username, final int orderId) {
    var refundOrder = refundOrderDao.getFlightRefundOrderDetail(orderId);

    if (StringUtils.isNotBlank(refundOrder.getExternalOrderNo())) {
      return JsonResult.createJsonResult(-1, "已存在外部订单号");
    }
    var rq = new OrderRefundRequest();

    rq.getMemberInfo().setAccountNumber(doGetEntCfg(enterpriseId, TMS_DEFAULT_LINK_MOBILE));

    rq.getRequest().setOrderChangeParameter(new OrderChangeParameter());
    if (refundOrder.getReasonCode() == 0) {
      rq.getRequest().getOrderChangeParameter().setRemark("自愿退票");
    } else {
      rq.getRequest().getOrderChangeParameter().setRemark(refundOrder.getReasonDesc());
    }

    var flightOrder = flightOrderDao.getOrderDetailByOrderNo(enterpriseId, refundOrder.getOrderNo());

    rq.getRequest().setOrderNo(flightOrder.getExternalOrderNo());
    rq.getRequest().setPnr(flightOrder.getBigPnrNo());

    Pax pax = new Pax();
    pax.setPassengerType("ADT");
    pax.setSurname(refundOrder.getPsgName());
    pax.setTicketNumber(refundOrder.getBalanceCode() + refundOrder.getTicketNo());
    rq.getRequest().getPassengers().add(pax);

    //记录查询日志
    final int queryId = userDao.createEtermCmdLog(enterpriseId, username, "CZ_NDC_创建退票单", flightOrder.getOrderNo());
    rq.getPayloadAttributes().setTransactionId(queryId + "");

    var ndcService = createNdcService(enterpriseId);
    if (ndcService == null) {
      return JsonResult.createJsonResult(-500, "该功能未配置启用");
    }
    try {
      var rs = ndcService.createRefundOrder(rq);
      userDao.updateEtermCmdLog(queryId, rs.getRequestStr(), rs.getResponseStr());

      if (SUCCESS.equalsIgnoreCase(rs.getStatus().getStatus())) {

        //rs.getResponse().getOrder().getOrderNo() 返回退票单号
        String externalOrderNo = rs.getResponse().getOrder().getOrderNo();
        int retCode = refundOrderDao.updateExternalOrderNo(enterpriseId, username, orderId,
                externalOrderNo, "保存外部退单号(" + externalOrderNo + ")");
        return JsonResult.createJsonResult(retCode, "外部退单号：" + externalOrderNo + ".");
      } else {
        final String msg = rs.getStatus().getErrorCode() + ": " + rs.getStatus().getErrorMessage();
        refundOrderDao.appendRefundOrderLog(enterpriseId, username, orderId, msg);

        return JsonResult.createJsonResult(-1, rs.getStatus().getErrorMessage());
      }
    } catch (Exception ex) {
      return JsonResult.createJsonResult(-500, "提交退票时出错：" + ex.getMessage());
    }
  }

  @Override
  public JsonResult syncNdcOrderRefundInfo(int enterpriseId, String username, int orderId) {
    var refundOrder = refundOrderDao.getFlightRefundOrderDetail(orderId);

    if (StringUtils.isBlank(refundOrder.getExternalOrderNo())) {
      return JsonResult.createJsonResult(-1, "外部订单号不存在");
    }

    var rq = new OrderRetrieveRequest();

    rq.getMemberInfo().setAccountNumber(doGetEntCfg(enterpriseId, TMS_DEFAULT_LINK_MOBILE));

    rq.getRequest().setOrderNo(refundOrder.getExternalOrderNo());

    var flightOrder = flightOrderDao.getOrderDetailByOrderNo(enterpriseId, refundOrder.getOrderNo());
    rq.getRequest().setPnr(flightOrder.getBigPnrNo());

    //记录查询日志
    final int queryId = userDao.createEtermCmdLog(enterpriseId, username, "CZ_NDC_查询退票单", refundOrder.getRefundOrderNo());
    rq.getPayloadAttributes().setTransactionId(queryId + "");

    var ndcService = createNdcService(enterpriseId);
    if (ndcService == null) {
      return JsonResult.createJsonResult(-500, "该功能未配置启用");
    }
    var rs = ndcService.searchOrder(rq);
    userDao.updateEtermCmdLog(queryId, rs.getRequestStr(), rs.getResponseStr());

    if (rs.getResponse() != null
            && rs.getResponse().getOrder() != null
            && refundOrder.getExternalOrderNo().equalsIgnoreCase(rs.getResponse().getOrder().getOrderNo())) {
      rs.getResponse().getOrder().setOrderType(1);
      final String orderStatus = rs.getResponse().getOrder().getStatus();
      final String orderStatusDesc = rs.getResponse().getOrder().getStatusDesc();

      int retCode = refundOrderDao.appendRefundOrderLog(enterpriseId, username, orderId,  refundOrder.getExternalOrderNo() + ": " + orderStatus + ", " + orderStatusDesc);

      if ("R".equalsIgnoreCase(orderStatus) || "P".equalsIgnoreCase(orderStatus) || "F".equalsIgnoreCase(orderStatus)) {
        //退票单已完成，校验金额是否相符
       if (rs.getResponse().getOrder().getTotalChangeAmount() == refundOrder.getAirRefundCharge()) {
         //退票完成，修改航司预退
         final double amount = rs.getResponse().getOrder().getBaseAmount();
         retCode = refundOrderDao.setFlightRefundAirlineRefundedAmount(enterpriseId, username, orderId, amount);
         if (retCode > 0) {
           retCode = refundOrderDao.setFlightRefundAirlineRefundedStatus(enterpriseId, username,  orderId );
         }

         if (retCode > 0) {
           return JsonResult.createJsonResult(1, "退票单状态同步成功");
         }
       } else {
         var content = rs.getResponse().getOrder().getTotalChangeAmount() + " != " + refundOrder.getAirRefundCharge();
         refundOrderDao.appendRefundOrderLog(enterpriseId, username, orderId,  content);
       }
      }

      return JsonResult.createJsonResult(1, "查询退票单成功(" + retCode + ")");
    } else {
      final String msg = rs.getStatus().getErrorCode() + ": " + rs.getStatus().getErrorMessage();

      return JsonResult.createJsonResult(-1, msg);
    }
  }

  @Override
  public JsonResult saveRefundOrderAttachment(int enterpriseId, String username, int orderId, List<OrderAttachment> attachments) {
    for (OrderAttachment oa : attachments) {
      oa.setOrderType(ORDER_TYPE_FLIGHT_REFUND);
      oa.setEnterpriseId(enterpriseId);
      oa.setOrderId(orderId);
    }

    int retCode = dao.saveRefundOrderAttachment(enterpriseId, username, orderId, attachments);

    return JsonResult.createJsonResult(retCode);
  }

  private String generateSmsContentByTemplate(int enterpriseId, int smsFormat, FlightRefundOrder order) {
    final String companySign = doGetEntCfg(enterpriseId, EnterpriseConfig.API_SMS_COMPANY_SIGN);
    final String psgName = order.getPsgName() + "(" + order.getIdNo() + ")";
    final String smsRouteInfo = SmsUtil.convertRefundOrder(order);
    final int price = (int) (order.getAirRefundCharge() + order.getServiceCharge());

    String smsContent = null;
    if (smsFormat == 0) {
      String ticketNo = order.getBalanceCode() + order.getTicketNo();
      smsContent = String.format(REFUND_SMS_TEMPLATE_1, companySign, psgName, smsRouteInfo, ticketNo, price);
    }

    return smsContent;
  }


}
